home *** CD-ROM | disk | FTP | other *** search
/ Turnbull China Bikeride / Turnbull China Bikeride - Disc 1.iso / DEMON / RISCOS2 / TCP_131S.ARC / c / ftpcli < prev    next >
Text File  |  1994-03-06  |  20KB  |  822 lines

  1. /* FTP client (interactive user) code */
  2. #define LINELEN         128     /* Length of command buffer */
  3. #include <stdio.h>
  4. #include <stdlib.h>
  5. #include <string.h>
  6. #include <time.h>
  7. #include <stdarg.h>
  8. #include "global.h"
  9. #include "mbuf.h"
  10. #include "domain.h"
  11. #include "netuser.h"
  12. #include "icmp.h"
  13. #include "timer.h"
  14. #include "tcp.h"
  15. #include "ftp.h"
  16. #include "session.h"
  17. #include "cmdparse.h"
  18. #include "misc.h"
  19. #include "Terminal.h"
  20.  
  21. extern struct session *current;
  22. struct session *current_ftp;
  23. extern char nospace[];
  24. extern char badhost[];
  25. static char notsess[]   = "Not an FTP session!\r\n";
  26. static char cantwrite[] = "Can't write %s\r\n";
  27. static char cantread[]  = "Can't read %s\r\n";
  28.  
  29. static int  donothing(int, char **);
  30. static int  doftpcd(int, char **);
  31. static int  domkdir(int, char **);
  32. static int  dormdir(int, char **);
  33. static int  doascii(int, char **);
  34. static int  dobinary(int, char **);
  35. static int  dotype(int, char **);
  36. static int  doget(int, char **);
  37. static int  dohash(int, char **);
  38. static int  dolist(int, char **);
  39. static int  dols(int, char **);
  40. static int  doput(int, char **);
  41. static void doreply(struct ftp *);
  42. static void ftpsetup(struct ftp *, void (*)(), void (*)(), void (*)());
  43. static void ftpccs(struct tcb *, char, char);
  44. static void ftpcds(struct tcb *, char, char);
  45. static int  sndftpmsg(struct ftp *, char *, ...); 
  46.  
  47. struct cmds ftpabort[] = {
  48.   "",             donothing,    0,    NULLCHAR,               NULLCHAR,
  49.   "abort",        doabort,      0,    NULLCHAR,               NULLCHAR,
  50.   "hash",         dohash,       2,    "hash lumpsize",        NULLCHAR,
  51.   NULLCHAR,       NULLFP,       0,    "Only valid command is \"abort\"", NULLCHAR,
  52. };
  53.  
  54. struct cmds ftpcmds[] = {
  55.   "",             donothing,    0,    NULLCHAR,               NULLCHAR,
  56.   "ascii",        doascii,      0,    NULLCHAR,               NULLCHAR,
  57.   "binary",       dobinary,     0,    NULLCHAR,               NULLCHAR,
  58.   "cd",           doftpcd,      2,    "cd <directory>",       NULLCHAR,
  59.   "dir",          dolist,       0,    NULLCHAR,               NULLCHAR,
  60.   "list",         dolist,       0,    NULLCHAR,               NULLCHAR,
  61.   "get",          doget,        2,    "get remotefile <localfile>",  NULLCHAR,
  62.   "hash",         dohash,       2,    "hash lumpsize",        NULLCHAR,
  63.   "image",        dobinary,     0,    NULLCHAR,               NULLCHAR,
  64.   "ls",           dols,         0,    NULLCHAR,               NULLCHAR,
  65.   "mkdir",        domkdir,      2,    "mkdir <directory>",    NULLCHAR,
  66.   "nlst",         dols,         0,    NULLCHAR,               NULLCHAR,
  67.   "rmdir",        dormdir,      2,    "rmdir <directory>",    NULLCHAR,
  68.   "put",          doput,        2,    "put localfile <remotefile>",  NULLCHAR,
  69.   "type",         dotype,       0,    NULLCHAR,               NULLCHAR,
  70.   NULLCHAR,       NULLFP,       0,    NULLCHAR,               NULLCHAR,
  71. };
  72.  
  73. /* Handle top-level FTP command */
  74. int doftp(int argc, char **argv)
  75. {
  76.   struct session *s;
  77.   struct ftp *ftp;
  78.   struct tcb *tcb;
  79.   struct socket lsocket,fsocket;
  80.  
  81.   lsocket.address = ip_addr;
  82.   lsocket.port = lport++;
  83.   if((fsocket.address = resolve(argv[1])) == 0)
  84.   {
  85.     cwprintf(NULL, badhost,argv[1]);
  86.     return 1;
  87.   }
  88.   if(argc < 3)
  89.     fsocket.port = FTP_PORT;
  90.   else
  91.     fsocket.port = atoi(argv[2]);
  92.  
  93.   /* Allocate a session control block */
  94.   if((s = newsession()) == NULLSESSION)
  95.   {
  96.     cwprintf(NULL, "Too many sessions\r\n");
  97.     return 1;
  98.   }
  99.   if((s->name = malloc((unsigned)strlen(argv[1])+1)) != NULLCHAR)
  100.     strcpy(s->name,argv[1]);
  101.   s->type = FTP;
  102.   s->parse = (void(*)())ftpparse;
  103.  
  104.   /* Allocate an FTP control block */
  105.   if((ftp = ftp_create(LINELEN)) == NULLFTP)
  106.   {
  107.     s->type = FREE;
  108.     cwprintf(NULL, nospace);
  109.     return 1;
  110.   }
  111.   ftp->window = Window_Open(s, "FTP", term_SIXTEEN | term_CARET);
  112.   if (ftp->window == NULL)
  113.   {
  114.     current = s;
  115.   }
  116.   ftp->state   = STARTUP_STATE;
  117.   s->cb.ftp    = ftp;     /* Downward link */
  118.   ftp->session = s;       /* Upward link */
  119.   s->window    = ftp->window;
  120.   ftp->session->echo = TRUE;
  121.  
  122.   /* Now open the control connection */
  123.   tcb = open_tcp(&lsocket, &fsocket, TCP_ACTIVE, 0, (void(*)())ftpccr, NULLVFP, (void(*)())ftpccs, 0,( char *)ftp);
  124.   ftp->control = tcb;
  125.   go(s);
  126.   return 0;
  127. }
  128. /* Parse user FTP commands */
  129. void ftpparse(struct session *active, char *line, int16 len)
  130. {
  131.   struct mbuf *bp;
  132.  
  133.   if (active == NULL)
  134.     active = current;
  135.   current_ftp = active;
  136.     
  137.   switch(active->cb.ftp->state)
  138.   {
  139.   case RECEIVING_STATE:
  140.   case SENDING_FILE_STATE:
  141.     /* The only command allowed in data transfer state is ABORT */
  142.     if (cmdparse(ftpabort, line, active->window) == -1)
  143.     {
  144.       cwprintf(active->window, "Transfer in progress; only ABORT is acceptable\r\n");
  145.     }
  146.     break;
  147.   case COMMAND_STATE:
  148.     /* Save it now because cmdparse modifies the original */
  149.     bp = qdata(line,len);
  150.  
  151.     if (cmdparse(ftpcmds, line, active->window) == -1)
  152.     {
  153.       /* Send it direct */
  154.       if(bp != NULLBUF)
  155.         send_tcp(active->cb.ftp->control,bp);
  156.       else
  157.         cwprintf(active->window, nospace);
  158.     } 
  159.     else
  160.     {
  161.       free_p(bp);
  162.     }
  163.     break;
  164.   case STARTUP_STATE:             /* Startup up autologin */
  165.     cwprintf(active->window, "Not connected yet, ignoring %s\r\n",line);
  166.     break;
  167.   case USER_STATE:                /* Got the user name */
  168.     line[len] = '\0';
  169.     sndftpmsg(active->cb.ftp,"USER %s",line);
  170.     break;
  171.   case PASS_STATE:                /* Got the password */
  172.     cooked();
  173.     active->raw = FALSE;
  174.     line[len] = '\0';
  175.     sndftpmsg(active->cb.ftp,"PASS %s",line);
  176.     break;
  177.   } 
  178. }
  179.  
  180. /* Handle null line to avoid trapping on first command in table */
  181. static int donothing(int argc, char **argv)
  182. {
  183.   argc = argc;
  184.   argv = argv;
  185.   return 0;
  186. }
  187.  
  188. /* Translate 'cd' to 'cwd' for convenience */
  189. static int doftpcd(int argc, char **argv)
  190. {
  191.   register struct ftp *ftp;
  192.  
  193.   argc = argc;
  194.  
  195.   ftp = current_ftp->cb.ftp;
  196.   return sndftpmsg(ftp,"CWD %s\r\n",argv[1]);
  197. }
  198.  
  199. /* Translate 'mkdir' to 'xmkd' for convenience */
  200. static int domkdir(int argc, char **argv)
  201. {
  202.   register struct ftp *ftp;
  203.  
  204.   argc = argc;
  205.  
  206.   ftp = current_ftp->cb.ftp;
  207.   return sndftpmsg(ftp,"XMKD %s\r\n",argv[1]);
  208. }
  209.  
  210. static int dohash(int argc, char **argv)
  211. {
  212.   register struct ftp *ftp;
  213.  
  214.   argc = argc;
  215.  
  216.   ftp = current_ftp->cb.ftp;
  217.   ftp->hash = atoi(argv[1]);
  218.   ftp->last = 0;
  219.   return(0);
  220. }
  221.  
  222. /* Translate 'rmdir' to 'xrmd' for convenience */
  223. static int dormdir(int argc, char **argv)
  224. {
  225.   register struct ftp *ftp;
  226.  
  227.   argc = argc;
  228.  
  229.   ftp = current_ftp->cb.ftp;
  230.   return sndftpmsg(ftp,"XRMD %s\r\n",argv[1]);
  231. }
  232.  
  233. static int dobinary(int argc, char **argv)
  234. {
  235.   register struct ftp *ftp;
  236.  
  237.   argc = argc;
  238.   argv = argv;
  239.  
  240.   ftp = current_ftp->cb.ftp;
  241.   ftp->type = IMAGE_TYPE;
  242.   sndftpmsg(ftp,"TYPE I\r\n");
  243.  
  244.   return(0);
  245. }
  246.  
  247. static int doascii(int argc, char **argv)
  248. {
  249.   register struct ftp *ftp;
  250.  
  251.   argc = argc;
  252.   argv = argv;
  253.  
  254.   ftp = current_ftp->cb.ftp;
  255.   ftp->type = ASCII_TYPE;
  256.   sndftpmsg(ftp,"TYPE A\r\n");
  257.  
  258.   return(0);
  259. }
  260.  
  261. /* Handle "type" command from user */
  262. static int dotype(int argc, char **argv)
  263. {
  264.   register struct ftp *ftp;
  265.  
  266.   ftp = current_ftp->cb.ftp;
  267.   if (argc < 2)
  268.   {
  269.     switch(ftp->type)
  270.     {
  271.     case IMAGE_TYPE:
  272.       cwprintf(ftp->window, "Image\r\n");
  273.       break;
  274.     case ASCII_TYPE:
  275.       cwprintf(ftp->window, "Ascii\r\n");
  276.       break;
  277.     }
  278.     return 0;
  279.   }
  280.   switch(*argv[1])
  281.   {
  282.   case 'i':
  283.   case 'b':
  284.     ftp->type = IMAGE_TYPE;
  285.     sndftpmsg(ftp,"TYPE I\r\n");
  286.     break;
  287.   case 'a':
  288.     ftp->type = ASCII_TYPE;
  289.     sndftpmsg(ftp,"TYPE A\r\n");
  290.     break;
  291.   case 'l':
  292.     ftp->type = IMAGE_TYPE;
  293.     sndftpmsg(ftp,"TYPE L %s\r\n",argv[2]);
  294.     break;
  295.   default:
  296.     cwprintf(ftp->window, "Invalid type %s\r\n",argv[1]);
  297.     return 1;
  298.   }
  299.   return 0;
  300. }
  301.  
  302. /* Start receive transfer. Syntax: get <remote name> [<local name>] */
  303. static int doget(int argc, char **argv)
  304. {
  305.   char *remotename, *temp, *cp, localname[256];
  306.   register struct ftp *ftp;
  307.   char *mode;
  308.  
  309.   ftp = current_ftp->cb.ftp;
  310.   if (ftp == NULLFTP)
  311.   {
  312.     cwprintf(ftp->window, notsess);
  313.     return 1;
  314.   }
  315.   remotename = argv[1];
  316.   if (argc < 3)
  317.   {
  318.     temp = strdup(remotename);
  319.     while (cp = strpbrk(temp, "\"[]|<>+=;,."), cp != NULL)
  320.       *cp = '/';
  321.     if (strlen(temp) > 10)
  322.       temp[10] = '\0';
  323.     sprintf(localname, "ftp:%s", temp);
  324.     free(temp);
  325.   }
  326.   else
  327.   {
  328.     if (strchr(argv[2], '.'))
  329.       strcpy(localname, argv[2]);
  330.     else
  331.       sprintf(localname, "ftp:%s", argv[2]);
  332.   }
  333.  
  334.   if (ftp->fp != NULLFILE && ftp->fp != stdout)
  335.     fclose(ftp->fp);
  336.   ftp->fp = NULLFILE;
  337.  
  338.   if(ftp->type == IMAGE_PENDING)
  339.   {
  340.     ftp->type = IMAGE_TYPE ;
  341.     sndftpmsg(ftp,"TYPE I\r\n");
  342.   }
  343.  
  344.   if (ftp->type == IMAGE_TYPE)
  345.     mode = binmode[WRITE_BINARY];
  346.   else
  347.     mode = "w";
  348.  
  349.   if ((ftp->fp = fopen(localname,mode)) == NULLFILE)
  350.   {
  351.     cwprintf(ftp->window, cantwrite,localname);
  352.     return 1;
  353.   }
  354.   ftp->last = 0;
  355.   ftp->state = RECEIVING_STATE;
  356.   ftpsetup(ftp,(void(*)())ftpdr, NULLVFP, (void(*)())ftpcds);
  357.  
  358.   /* Generate the command to start the transfer */
  359.   return sndftpmsg(ftp,"RETR %s\r\n",remotename);
  360. }
  361.  
  362. /* List remote directory. Syntax: dir <remote directory/file> [<local name>] */
  363. static int dolist(int argc, char **argv)
  364. {
  365.   char localname[256];
  366.   register struct ftp *ftp;
  367.  
  368.   ftp = current_ftp->cb.ftp;
  369.   if(ftp == NULLFTP)
  370.   {
  371.     cwprintf(ftp->window, notsess);
  372.     return 1;
  373.   }
  374.   if(ftp->fp != NULLFILE && ftp->fp != stdout)
  375.     fclose(ftp->fp);
  376.   ftp->fp = NULLFILE;
  377.  
  378.   if(argc < 3)
  379.   {
  380.     ftp->fp = stdout;
  381.   } 
  382.   else
  383.   {
  384.     if (strchr(argv[2], '.'))
  385.       strcpy(localname, argv[2]);
  386.     else
  387.       sprintf(localname, "ftp:%s", argv[2]);
  388.       
  389.     if ((ftp->fp = fopen(argv[2], "w")), ftp->fp == NULLFILE)
  390.     {
  391.       cwprintf(ftp->window, cantwrite,argv[2]);
  392.       return 1;
  393.     }
  394.   }
  395.   ftp->state = RECEIVING_STATE;
  396.   ftpsetup(ftp,(void(*)())ftpdr,NULLVFP,(void(*)())ftpcds);
  397.   /* Generate the command to start the transfer
  398.      It's done this way to avoid confusing the 4.2 FTP server
  399.      if there's no argument */
  400.   if(argc > 1)
  401.   {
  402.     if ( ftp->type == IMAGE_TYPE )
  403.     {
  404.       ftp->type = IMAGE_PENDING ;
  405.       sndftpmsg(ftp,"TYPE A\r\n");
  406.     }
  407.     return sndftpmsg(ftp,"LIST %s\r\n",argv[1]);
  408.   }
  409.   else
  410.   {
  411.     if ( ftp->type == IMAGE_TYPE )
  412.     {
  413.       ftp->type = IMAGE_PENDING ;
  414.       sndftpmsg(ftp,"TYPE A\r\n");
  415.     }
  416.       return sndftpmsg(ftp,"LIST\r\n","");
  417.   }
  418. }
  419. /* Abbreviated (name only) list of remote directory.
  420.  * Syntax: ls <remote directory/file> [<local name>]
  421.  */
  422. static int dols(int argc, char **argv)
  423. {
  424.   char localname[256];
  425.   register struct ftp *ftp;
  426.  
  427.   ftp = current_ftp->cb.ftp;
  428.   if(ftp == NULLFTP)
  429.   {
  430.     cwprintf(ftp->window, notsess);
  431.     return 1;
  432.   }
  433.   if(ftp->fp != NULLFILE && ftp->fp != stdout)
  434.     fclose(ftp->fp);
  435.   ftp->fp = NULLFILE;
  436.  
  437.   if(argc < 3)
  438.   {
  439.     ftp->fp = stdout;
  440.   } 
  441.   else
  442.   {
  443.     if (strchr(argv[2], '.'))
  444.       strcpy(localname, argv[2]);
  445.     else
  446.       sprintf(localname, "ftp:%s", argv[2]);
  447.       
  448.     if ((ftp->fp = fopen(argv[2], "w")), ftp->fp == NULLFILE)
  449.     {
  450.       cwprintf(ftp->window, cantwrite,argv[2]);
  451.       return 1;
  452.     }
  453.   }
  454.   ftp->state = RECEIVING_STATE;
  455.   ftpsetup(ftp,(void(*)())ftpdr,NULLVFP,(void(*)())ftpcds);
  456.   /* Generate the command to start the transfer */
  457.   if(argc > 1)
  458.   {
  459.     if ( ftp->type == IMAGE_TYPE )
  460.     {
  461.       ftp->type = IMAGE_PENDING ;
  462.       sndftpmsg(ftp,"TYPE A\r\n");
  463.     }
  464.     return sndftpmsg(ftp,"NLST %s\r\n",argv[1]);
  465.   }
  466.   else
  467.   {
  468.     if ( ftp->type == IMAGE_TYPE )
  469.     {
  470.       ftp->type = IMAGE_PENDING ;
  471.       sndftpmsg(ftp,"TYPE A\r\n");
  472.     }
  473.     return sndftpmsg(ftp,"NLST\r\n","");
  474.   }
  475. }
  476. /* Start transmit. Syntax: put <local name> [<remote name>] */
  477. static int doput(int argc, char **argv)
  478. {
  479.   char *remotename,*localname;
  480.   char *mode;
  481.   struct ftp *ftp;
  482.  
  483.   if((ftp = current_ftp->cb.ftp) == NULLFTP)
  484.   {
  485.     cwprintf(ftp->window, notsess);
  486.     return 1;
  487.   }
  488.   localname = argv[1];
  489.   if(argc < 3)
  490.     remotename = localname;
  491.   else
  492.       remotename = argv[2];
  493.  
  494.   if(ftp->fp != NULLFILE && ftp->fp != stdout)
  495.     fclose(ftp->fp);
  496.  
  497.   if(ftp->type == IMAGE_PENDING)
  498.   {
  499.     ftp->type = IMAGE_TYPE ;
  500.     sndftpmsg(ftp,"TYPE I\r\n");
  501.   }
  502.  
  503.   if(ftp->type == IMAGE_TYPE)
  504.     mode = binmode[READ_BINARY];
  505.   else
  506.     mode = "r";
  507.  
  508.   if((ftp->fp = fopen(localname,mode)) == NULLFILE)
  509.   {
  510.     cwprintf(ftp->window, cantread,localname);
  511.     return 1;
  512.   }
  513.   ftp->last = 0;
  514.   ftp->state = SENDING_FILE_STATE;
  515.   ftpsetup(ftp, NULLVFP, (void(*)())ftpdt, (void(*)())ftpcds);
  516.  
  517.   /* Generate the command to start the transfer */
  518.   return sndftpmsg(ftp,"STOR %s\r\n",remotename);
  519. }
  520. /* Abort a GET or PUT operation in progress. Note: this will leave
  521.  * the partial file on the local or remote system
  522.  */
  523. int doabort(int argc, char **argv)
  524. {
  525.   register struct ftp *ftp;
  526.  
  527.   argc = argc;
  528.   argv = argv;
  529.  
  530.   ftp = current_ftp->cb.ftp;
  531.  
  532.   /* Close the local file */
  533.   if(ftp->fp != NULLFILE && ftp->fp != stdout)
  534.     fclose(ftp->fp);
  535.   ftp->fp = NULLFILE;
  536.  
  537.   switch(ftp->state)
  538.   {
  539.   case SENDING_FILE_STATE:
  540.     /* Send a premature EOF.
  541.        Unfortunately we can't just reset the connection
  542.        since the remote side might end up waiting forever
  543.        for us to send something. */
  544.     close_tcp(ftp->data);
  545.     cwprintf(ftp->window, "Put aborted\r\n");
  546.     break;
  547.   case RECEIVING_STATE:
  548.     /* Just exterminate the data channel TCB; this will
  549.                      * generate a RST on the next data packet which will
  550.                      * abort the sender
  551.                      */
  552.     del_tcp(ftp->data);
  553.     ftp->data = NULLTCB;
  554.     cwprintf(ftp->window, "Get aborted\r\n");
  555.     break;
  556.   }
  557.   ftp->state = COMMAND_STATE;
  558.   return 0;
  559. }
  560. /* create data port, and send PORT message */
  561. static void ftpsetup(struct ftp *ftp, void (*recv)(),
  562. void (*send)(), void (*state)())
  563. {
  564.   struct socket lsocket;
  565.   struct mbuf *bp;
  566.  
  567.   lsocket.address = ip_addr;
  568.   lsocket.port = lport++;
  569.  
  570.   /* Compose and send PORT a,a,a,a,p,p message */
  571.  
  572.   if((bp = alloc_mbuf(35)) == NULLBUF)
  573.   {   /* 5 more than worst case */
  574.     cwprintf(ftp->window, nospace);
  575.     return;
  576.   }
  577.   /* I know, this looks gross, but it works! */
  578.   sprintf(bp->data,"PORT %u,%u,%u,%u,%u,%u\r\n",
  579.   hibyte(hiword(lsocket.address)),
  580.   lobyte(hiword(lsocket.address)),
  581.   hibyte(loword(lsocket.address)),
  582.   lobyte(loword(lsocket.address)),
  583.   hibyte(lsocket.port),
  584.   lobyte(lsocket.port));
  585.   bp->cnt = strlen(bp->data);
  586.   send_tcp(ftp->control,bp);
  587.  
  588.   /* Post a listen on the data connection */
  589.   ftp->data = open_tcp(&lsocket,NULLSOCK,TCP_PASSIVE,0,
  590.   recv,send,state,0,(char *)ftp);
  591. }
  592. /* FTP Client Control channel Receiver upcall routine */
  593. void ftpccr(register struct tcb *tcb, int16 cnt)
  594. {
  595.   extern int ttyflow;
  596.   struct mbuf *bp;
  597.   struct ftp *ftp;
  598.   char c;
  599.  
  600.   if((ftp = (struct ftp *)tcb->user) == NULLFTP)
  601.   {
  602.     /* Unknown connection; kill it */
  603.     close_tcp(tcb);
  604.     return;
  605.   }
  606.   /* Hold output if we're not the current session */
  607.   if (ftp->window == NULL && (mode != CONV_MODE || current == NULLSESSION 
  608.       || ttyflow == 0 || current->cb.ftp != ftp))
  609.     return;
  610.  
  611.   if(recv_tcp(tcb,&bp,cnt) > 0)
  612.   {
  613.     while(pullone(&bp,&c) == 1)
  614.   {
  615.       switch(c)
  616.   {
  617.       case '\n':      /* Complete line; process it */
  618.  
  619.         ftp->buf[ftp->cnt] = '\0';
  620.         doreply(ftp);
  621.         ftp->cnt = 0;
  622.         break;
  623.       default:
  624.         if(ftp->cnt != LINELEN-1)
  625.           ftp->buf[ftp->cnt++] = c;
  626.         break;
  627.       }
  628.     }
  629.   }
  630. }
  631.  
  632. /* Process replies from the server */
  633. static void doreply(register struct ftp *ftp)
  634. {
  635.   char **s;
  636.  
  637.   cwprintf(ftp->window, "%s\r\n",ftp->buf);
  638.  
  639.   if(ftp->cnt < 3)
  640.     return;
  641.   if(ftp->buf[3] == '-')
  642.     return;
  643.   switch(ftp->state)
  644.   {
  645.   case SENDING_FILE_STATE:
  646.   case RECEIVING_STATE:
  647.     if (ftp->buf[0] == '5') doabort(0, s);
  648.     break;
  649.   case STARTUP_STATE:
  650.     if (strncmp(ftp->buf, "220", 3) == 0)
  651.   {
  652.       ftp->state = USER_STATE;
  653.       cwprintf(ftp->window, "Enter user name: ");
  654.     } 
  655.     else ftp->state = COMMAND_STATE;
  656.     break;
  657.   case USER_STATE:
  658.     if (strncmp(ftp->buf, "331", 3) == 0)
  659.   {
  660.       ftp->state = PASS_STATE;
  661.       noecho();
  662.       ftp->session->echo = FALSE;
  663.       cwprintf(ftp->window, "Password: ");
  664.     } 
  665.     else ftp->state = COMMAND_STATE;
  666.     break;
  667.   case PASS_STATE:
  668.     echo();
  669.     ftp->session->echo = TRUE;
  670.     ftp->state = COMMAND_STATE;
  671.   case COMMAND_STATE:
  672.     cwprintf(ftp->window, "ftp> ");
  673.     break;
  674.   }
  675. }
  676.  
  677. /* FTP Client Control channel State change upcall routine */
  678. static void ftpccs(register struct tcb *tcb, char old, char new)
  679. {
  680.   extern int ttyflow;
  681.   struct ftp *ftp;
  682.   char notify = 0;
  683.   extern char *tcpstates[];
  684.   extern char *reasons[];
  685.   extern char *unreach[];
  686.   extern char *exceed[];
  687.  
  688.   old = old;
  689.  
  690.   /* Can't add a check for unknown connection here, it would loop
  691.            * on a close upcall! We're just careful later on.
  692.            */
  693.   ftp = (struct ftp *)tcb->user;
  694.  
  695.   if (ftp->window || (ttyflow && current != NULLSESSION && current->cb.ftp == ftp))
  696.     notify = 1;
  697.  
  698.   switch(new)
  699.   {
  700.   case CLOSE_WAIT:
  701.     if(notify)
  702.       cwprintf(ftp->window, "%s\r\n",tcpstates[new]);
  703.     close_tcp(tcb);
  704.     break;
  705.   case CLOSED:    /* heh heh */
  706.     if (notify)
  707.     {
  708.       cwprintf(ftp->window, "%s (%s",tcpstates[new],reasons[tcb->reason]);
  709.       if (tcb->reason == NETWORK)
  710.       {
  711.         switch(tcb->type)
  712.         {
  713.         case DEST_UNREACH:
  714.           cwprintf(ftp->window, ": %s unreachable",unreach[tcb->code]);
  715.           break;
  716.         case TIME_EXCEED:
  717.           cwprintf(ftp->window, ": %s time exceeded",exceed[tcb->code]);
  718.           break;
  719.         }
  720.       }
  721.       cwprintf(ftp->window, ")\r\n");
  722.       cmdmode();
  723.     }
  724.     del_tcp(tcb);
  725.     if(ftp != NULLFTP)
  726.     {
  727.       if (ftp->window)
  728.       {
  729.         ftp->window->Attr = ATTR_REVERSE;
  730.         ftp->window->Flags.flags.dont_destroy = FALSE;
  731.         ftp->window->Session = NULL;
  732.         cwprintf(ftp->window, "\nThis session has finished, please close the window\n");
  733.       }
  734.       ftp_delete(ftp);
  735.     }
  736.     break;
  737.   default:
  738.     if(notify)
  739.       cwprintf(ftp->window, "%s\r\n",tcpstates[new]);
  740.     break;
  741.   }
  742. }
  743. /* FTP Client Data channel State change upcall handler */
  744. static void ftpcds(struct tcb *tcb, char old, char new)
  745. {
  746.   extern int ttyflow;
  747.   struct ftp *ftp;
  748.  
  749.   old = old;
  750.  
  751.   if ((ftp = (struct ftp *)tcb->user) == NULLFTP)
  752.   {
  753.     /* Unknown connection, kill it */
  754.     close_tcp(tcb);
  755.     return;
  756.   }
  757.   switch(new)
  758.   {
  759.   case FINWAIT2:
  760.   case TIME_WAIT:
  761.     if(ftp->state == SENDING_FILE_STATE)
  762.     {
  763.       /* We've received an ack of our FIN, so
  764.                                * return to command mode
  765.                                */
  766.       ftp->state = COMMAND_STATE;
  767.       if(ftp->window != NULL || (ttyflow && current != NULLSESSION && current->cb.ftp == ftp))
  768.       {
  769.         if ( ftp->hash > 0 )
  770.           cwputchar(ftp->window, '\n');
  771.         cwprintf(ftp->window, "Put complete, %lu bytes sent\r\n",
  772.         tcb->snd.una - tcb->iss - 2);
  773.       }
  774.     }
  775.     break;          
  776.   case CLOSE_WAIT:
  777.     close_tcp(tcb);
  778.     if (ftp->state == RECEIVING_STATE)
  779.     {
  780.       /* End of file received on incoming file */
  781.       if(ftp->fp != stdout)
  782.         fclose(ftp->fp);
  783.       ftp->fp = NULLFILE;
  784.       ftp->state = COMMAND_STATE;
  785.       if (ftp->window != NULL || (ttyflow && current != NULLSESSION && current->cb.ftp == ftp))
  786.       {
  787.         if ( ftp->hash > 0 )
  788.           cwputchar(ftp->window, '\n');
  789.         cwprintf(ftp->window, "Get complete, %lu bytes received\r\n",
  790.         tcb->rcv.nxt - tcb->irs - 2);
  791.       }
  792.     }
  793.     break;
  794.   case CLOSED:
  795.     ftp->data = NULLTCB;
  796.     del_tcp(tcb);
  797.     break;
  798.   }
  799. }
  800. /* Send a message on the control channel */
  801. static int sndftpmsg(struct ftp *ftp, char *fmt, ...)
  802. {
  803.   va_list argptr;
  804.   struct mbuf *bp;
  805.   int16 len;
  806.  
  807.   va_start(argptr,fmt);
  808.   len = strlen(fmt) + strlen(va_arg(argptr,char *)) + 10;   /* fudge factor */
  809.   va_end(argptr);
  810.   if((bp = alloc_mbuf(len)) == NULLBUF)
  811.   {
  812.     cwprintf(ftp->window, nospace);
  813.     return 1;
  814.   }
  815.   va_start(argptr,fmt);
  816.   vsprintf(bp->data,fmt,argptr);
  817.   va_end(argptr);
  818.   bp->cnt = strlen(bp->data);
  819.   send_tcp(ftp->control,bp);
  820.   return 0;
  821. }
  822.